# Copyright (C) 2006  Apptility LLC  http://www.apptility.com
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA


# Filters added to this controller will be run for all controllers in the application.
# Likewise, all the methods added will be available for all controllers.
# 

class AjubyDataAuthorize 
    
    
    $ADA_CODE_INCOMPLETE_DATA = 100
    $ADA_CODE_AUTH_COMPLETE = 200
    $ADA_CODE_NOT_AUTHORIZED = 300
    $data_access_actions  
    $data_access_modules
    
    def self.execute(controller, action, current_user, params)
      do_data_auth_and_get_response(controller, action, current_user, params)
    end
    
	def self.do_data_auth_and_get_response(controller, action, current_user,params)
	  
	  enable_data_access_check = AJUBY_CONFIG['enable_data_access_check']['value']
	  if(enable_data_access_check!=nil and enable_data_access_check=='false')
        AjubyLogger.logInfo "[AjubyDataAuthorize] Data access check disabled globaly, to enable the data access go to ajubyconfig.yml and change the property 'enable_data_access_check' to true"
        return
      end
      
      $data_access_actions = get_data_access_actions	  
      $data_access_modules = get_data_access_modules

      return if !$data_access_actions.include?(action) or !$data_access_modules.include?(controller)
      
      #AjubyLogger.logInfo "$data_access_actions>>>>>>>>>:#{$data_access_actions}>>>>>>>$data_access_modules>>>>>>>:#{$data_access_modules}"	
	  return if current_user == nil
      @data_auth_result = nil
      roles = current_user.roles
      #AjubyLogger.logInfo "roles #{roles}"
      for role in roles
        role_id = role.id
        #AjubyLogger.logInfo "role_id #{role_id}"
        permission = get_permission(controller, action)
        if permission != nil
          #AjubyLogger.logInfo "Permission #{permission.id}"
          #@dataccess = Dataaccess.find_first_by_role_id_and_permission_id(role_id, permission.id)
          @dataccess = Dataaccess.find(:first, :conditions => [ "role_id =? and permission_id=?", role_id, permission.id])
          if @dataccess!=nil
            #AjubyLogger.logInfo "@dataccess>> #{@dataccess.data_flag_id}"
            @data_auth_result = check_and_get_auth_data_result(@dataccess, controller, action, role_id, current_user,params)
        end
       end
      end
      
      #AjubyLogger.logInfo "@data_auth_result >>>>>>>>>>> #{@data_auth_result}"
      if @data_auth_result==nil
        # TODO show all the records, this might change or we have to look into this in detail later
        @data_auth_result = get_all_data_auth_result(controller)
      end
        
      return @data_auth_result
	end
	

    def self.check_and_get_auth_data_result (dataccess, controller, action, role_id, current_user,params)
      
      @auth_data_res = nil
      if action == 'list'
        @auth_data_res = handle_list_action(dataccess, controller, action, role_id, current_user, params)
      end
      if action == 'edit'
        @auth_data_res = handle_edit_action(dataccess, controller, action, role_id, current_user, params)
      end
      if action == 'delete'
        @auth_data_res = handle_delete_action(dataccess, controller, action, role_id, current_user, params)
      end
      if action == 'show'
        @auth_data_res = handle_show_action(dataccess, controller, action, role_id, current_user, params)
      end
      
      
      return @auth_data_res        
    end 
  
    #handle list action data authorization  
    def self.handle_list_action (dataccess, controller, action, role_id, current_user, params)
      #AjubyLogger.logInfo "dataccess.data_flag_id >>>>>>>>>>> #{dataccess.data_flag_id}"
      if dataccess.data_flag_id==1 # all
       @auth_data_res = get_all_data_auth_result(controller)
     end
     if dataccess.data_flag_id==2 # none
        @auth_data_res = get_none_data_auth_result(controller)
     end
     if dataccess.data_flag_id==3 # owner
        @auth_data_res = get_owner_data_auth_result(controller, current_user)
     end
     if dataccess.data_flag_id==4 # collection
        @auth_data_res = get_collection_data_auth_result(controller, action, role_id)
        #AjubyLogger.logInfo "@auth_data_res >>>>> #{@auth_data_res}" 
      end
      #AjubyLogger.logInfo "RETURNING @auth_data_res >>>>> #{@auth_data_res}" 
      return @auth_data_res
    end       	
   	
    def self.handle_edit_action (dataccess, controller, action, role_id, current_user, params)
   	  @id = params[:id]
     if dataccess.data_flag_id==1 # all
       @auth_data_res = get_all_data_auth_result(controller)
     end
     if dataccess.data_flag_id==2 # none
        @auth_data_res = get_none_data_auth_result(controller)
     end
     if dataccess.data_flag_id==3 # owner
        @auth_data_res = get_owner_data_auth_result(controller, current_user)
     end
     if dataccess.data_flag_id==4 # collection
        @auth_data_res = get_collection_data_auth_result(controller, action, role_id)
      end
      return @auth_data_res   	  
    end
       	
    def self.handle_delete_action (dataccess, controller, action, role_id, current_user, params)
   	  @id = params[:id]
     if dataccess.data_flag_id==1 # all
       @auth_data_res = get_all_data_auth_result(controller)
     end
     if dataccess.data_flag_id==2 # none
        @auth_data_res = get_none_data_auth_result(controller)
     end
     if dataccess.data_flag_id==3 # owner
        @auth_data_res = get_owner_data_auth_result(controller, current_user)
     end
     if dataccess.data_flag_id==4 # collection
        @auth_data_res = get_collection_data_auth_result(controller, action, role_id)
      end
      return @auth_data_res   	  
    end

    def self.handle_show_action (dataccess, controller, action, role_id, current_user, params)
   	  @id = params[:id]
     if dataccess.data_flag_id==1 # all
       @auth_data_res = get_all_data_auth_result(controller)
     end
     if dataccess.data_flag_id==2 # none
        @auth_data_res = get_none_data_auth_result(controller)
     end
     if dataccess.data_flag_id==3 # owner
        @auth_data_res = get_owner_data_auth_result(controller, current_user)
     end
     if dataccess.data_flag_id==4 # collection
        @auth_data_res = get_collection_data_auth_result(controller, action, role_id)
      end
      return @auth_data_res   	  
    end
    
   	def self.get_all_data_auth_result (controller)
   	  @list = get_model_all_records(controller)
   	  @auth_data_res =  AjubyDataAuthResult.new(@list,$ADA_CODE_AUTH_COMPLETE)
   	  #AjubyLogger.logInfo "@auth_data_res ALL #{@auth_data_res}"
   	  return @auth_data_res
   	end

   	def self.get_none_data_auth_result (controller)
   	  @auth_data_res = AjubyDataAuthResult.new(Array.new(),$ADA_CODE_NOT_AUTHORIZED)
   	  #AjubyLogger.logInfo "@auth_data_res NONE #{@auth_data_res}"
   	  return @auth_data_res
   	end

   	def self.get_owner_data_auth_result (controller, current_user)
   	  model = get_model_from_string(controller)
   	  @list = model.find_all_by_created_by(current_user.id)
   	  return AjubyDataAuthResult.new(@list,$ADA_CODE_AUTH_COMPLETE)
   	end
   	

   	def self.get_collection_data_auth_result (controller, action, role_id)
   	  data_collection_ids = find_by_rima(role_id, controller, action)
   	  #AjubyLogger.logInfo "data_collection_ids >>>> #{data_collection_ids}"
   	  @list = Array.new()
   	  # TODO, better way to do this, using associations
   	  if data_collection_ids!=nil
   	      for data_collection_id in data_collection_ids
   	        @model = get_model_record(controller, data_collection_id)
   	        #AjubyLogger.logInfo "@model<<>>data_collection_id:  >>>> #{@model}<<<<>>>>> #{data_collection_id}"
   	        @list.push(@model) if @model!=nil
     	  end
      end
      #AjubyLogger.logInfo "@lis >>>>> #{@list}" 
      return AjubyDataAuthResult.new(@list,$ADA_CODE_AUTH_COMPLETE)	  
   	end
   	
   	
	def self.get_model_from_string(controller)
       model_name = controller.capitalize
       @model = Object.const_get(model_name)
       return @model
    end
    
    def self.get_model_all_records(controller)
      model = get_model_from_string(controller)
      return model.find(:all)
    end

    def self.get_model_record(controller, id)
      model = get_model_from_string(controller)
    
      @mode_record = nil
      begin  
        @mode_record = model.find(id)
      rescue
        
      end  
      return @mode_record
    end
        
   def self.get_permission(module_name, data_access_action)
    @permission = Permission.find(:first, :conditions => [ "controller =? and action=?", module_name, data_access_action])
    return @permission  
   end 
  
    def self.find_by_rima(role_id, module_name, data_access_action)
      data_collection_from_db = DataCollection.find_all_by_role_id_and_module_and_action(role_id, module_name, data_access_action)
      # TODO this can be improved, you can directly collect the collection_id from returned records
      saved_data_collection = Array.new()
      count=0
      
      if(data_collection_from_db!=nil)
        for data_collection in data_collection_from_db
          saved_data_collection.push(data_collection.collection_id) 
        end  
      end
      return saved_data_collection
   end
  
   def self.do_auth_and_aggregate(controller, action, current_user, superset_list)
    @data_auth_result = do_data_auth_and_get_response(controller, action, current_user)
    if @data_auth_result!=nil
       @real_list = @data_auth_result.list
       @temp_list = Array.new()
       if @real_list!=nil
          if @real_list.size == 0 # that means either collection or owner or none
              superset_list = @real_list
          else
            for @real_obj in @real_list
              for superset_obj in superset_list
                if superset_obj.id == @real_obj.id
                   @temp_list.push(@real_obj)
                end   
              end
            end
          end
          superset_list = @temp_list
       end
    end 
    return superset_list     
   end
   
   
   def self.get_data_access_modules
      if AjubyGlobalConfig.instance.functional_modules_list ==nil
        @appmodules = AppModule.find(:all, :conditions => [ "usage_type ='F'"])
        if @appmodules!=nil
          @functional_modules_list  = Array.new()
          for @appmodule in @appmodules
              @functional_modules_list.push(@appmodule.name)
          end
          AjubyGlobalConfig.instance.init_functional_modules_list(@functional_modules_list)
        end  
      end
      return AjubyGlobalConfig.instance.functional_modules_list
   end
   
   def self.get_data_access_actions
      if AjubyGlobalConfig.instance.data_auth_actions ==nil
        @data_auth_actions = ["list" , "edit" , "show", "delete"]
        AjubyGlobalConfig.instance.init_data_auth_actions(@data_auth_actions)
      end
      return AjubyGlobalConfig.instance.data_auth_actions    
   end  
   
    
end

